package com.young.context;

import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;

import java.util.HashMap;
import java.util.Map;


public final class ContextEnvironmentTool {

    public static final String GLOBAL_FIRST = "global first";

    public static final String GLOBAL_LAST = "global last";

    private static final String PROFILE = "profile";

    private static final String CLOUD = "cloud";

    //集群分组名称
    public static final String GROUP = "group";

    //系统变量
    public static final String GROUP_SP_KEY = "GROUP";

    private static final String CLOUD_SP_KEY = "CLOUD";

    private static final String NAMESPACE_APPLICATION = "spring.application";

    private static final String PREFER_PROFILE = "prefer-profile";

    enum Policy {
        FIRST,
        LAST
    }
    /**
     * 检测顺序：系统变量[profile]、yml配置[spring.application.prefer-profile]、env[spring.profiles.active]
     * 如果env中指定了多个profiles，则最后一个值被采用
     * 为了避免多个值时出现不确定性，可以使用"spring.application.prefer-profile"指定
     *
     * @param environment
     * @return
     */
    public static String preferProfile(final Environment environment) {
        return profile(environment).prefer();
    }


    public static Profile profile(final Environment environment) {
        String source = environment.getProperty(PROFILE);//--profile
        if (source == null) {
            source = environment.getProperty(NAMESPACE_APPLICATION + "." + PREFER_PROFILE);
        }
        if (source == null) {
            String[] profiles = environment.getActiveProfiles();
            if (profiles.length == 0) {
                //根据部署机器特性自动选择
                String hostName = InetTool.getHostName(true);
                if (hostName.contains(".prod.")) {
                    return Profile.PROD;
                } else if (hostName.contains(".pre.")) {
                    return Profile.PRE;
                } else if (hostName.contains(".beta.")) {
                    return Profile.BETA;
                } else if (hostName.contains(".test.")) {
                    return Profile.TEST;
                } else if (hostName.contains(".dev.")) {
                    return Profile.DEV;
                }
                profiles = environment.getDefaultProfiles();
            }
            source = profiles[profiles.length - 1];//取最后一个
        }
        return Profile.profileOf(source);
    }

    /**
     * 从环境变量中取出部署平台,aws、ali、ten、default
     * @param environment
     * @return
     */
    public static String cloud(final Environment environment) {
        String source = environment.getProperty(CLOUD);//--cloud
        if (source != null) {
            return source;
        }

        source = environment.getProperty(CLOUD_SP_KEY);
        if (source != null) {
            return source;
        }
        String hostName = InetTool.getHostName(true);
        //根据hostname推断
        if (hostName.contains(".aws.")) {
            source = Cloud.AWS.code;
        } else if (hostName.contains(".ali.")) {
            source = Cloud.ALI.code;
        } else if (hostName.contains(".ten.")) {
            source = Cloud.TEN.code;
        } else {
            source = Cloud.DEFAULT.code;
        }
        return source;
    }

    public static void putLast(Environment environment, String sourceName, Map<String, Object> properties) {
        if (properties == null || properties.isEmpty()) {
            return;
        }
        MapPropertySource source = getLast(environment, sourceName);
        if (source == null) {
            return;
        }
        Map<String, Object> mapper = source.getSource();
        mapper.putAll(properties);
        mapper.entrySet().removeIf(entry -> entry.getValue() == null);
    }

    /**
     * 获取指定sourceName的propertySource，如果尚未构建，则添加到last
     *
     * @param environment
     * @return
     */
    public static MapPropertySource getLast(Environment environment, String sourceName) {
        return getLast(environment, sourceName, false);
    }


    /**
     * 获取指定sourceName的propertySource，
     * 1）如果尚未构建，则添加到last
     * 2）如果已构建，且replacement=true，则直接覆盖并返回一个新的空的propertySource
     *
     * @param environment
     * @return
     */
    public static MapPropertySource getLast(Environment environment, String sourceName, boolean replacement) {
        return getSource(environment, sourceName, Policy.LAST, replacement);
    }

    private static MapPropertySource getSource(Environment environment, String sourceName, Policy policy, boolean replacement) {
        if (environment instanceof ConfigurableEnvironment) {
            MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();

            if (propertySources.contains(sourceName)) {
                if (replacement) {
                    MapPropertySource source = new MapPropertySource(sourceName, new HashMap<>());
                    propertySources.replace(sourceName, source);
                    return source;
                }
                return (MapPropertySource) propertySources.get(sourceName);
            }

            MapPropertySource source = new MapPropertySource(sourceName, new HashMap<>());
            switch (policy) {
                case LAST:
                    propertySources.addLast(source);
                    break;
                case FIRST:
                    propertySources.addFirst(source);
                    break;
            }
            return source;
        }
        return null;
    }

    /**
     * 只能外部传入，部署集群组
     */
    public static String preferGroup(final Environment environment) {
        String source = environment.getProperty(GROUP);//--group
        if (source != null) {
            return source;
        }
        return environment.getProperty(GROUP_SP_KEY);
    }

}
